// controllers/pdf_generator.go
package controllers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"myapi/config"
	"myapi/repositories"
	"myapi/utils"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
)

// PDFController 处理PDF生成相关请求
type PDFController struct {
	// 可以添加需要的仓库
	scoreRepo   repositories.ScoreRepository
	userRepo    repositories.UserRepository
	subjectRepo repositories.SubjectRepository
	orderRepo   repositories.OrderRepository
}

// NewPDFController 创建PDF控制器实例
func NewPDFController() *PDFController {
	return &PDFController{
		scoreRepo:   repositories.ScoreRepository{},
		userRepo:    repositories.UserRepository{},
		subjectRepo: repositories.SubjectRepository{},
		orderRepo:   repositories.OrderRepository{},
	}
}

// GenerateOrderPDF 根据ID生成订单PDF
func (c *PDFController) GenerateOrderPDF(ctx *gin.Context) {
	// 获取ID参数
	idStr := ctx.Query("id")
	if idStr == "" {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "缺少ID参数"})
		return
	}

	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "无效的ID格式"})
		return
	}

	// 根据ID从数据库获取订单信息
	order, err := c.orderRepo.FindByID(uint(id))
	if err != nil {
		ctx.JSON(http.StatusNotFound, gin.H{"error": "订单不存在: " + err.Error()})
		return
	}

	// 初始化字体
	if err := utils.InitPDFFonts(); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "初始化字体失败: " + err.Error()})
		return
	}

	// 转换订单项数据为PDF需要的格式
	items := []map[string]interface{}{}
	for _, item := range order.Items {
		items = append(items, map[string]interface{}{
			"name":     item.ProductName,
			"spec":     item.ProductSpec,
			"quantity": fmt.Sprintf("%d", item.Quantity),
			"price":    fmt.Sprintf("%.2f", item.UnitPrice),
			"amount":   fmt.Sprintf("%.2f", item.Amount),
		})
	}

	qrCodePath, err := c.getWechatQRCode(order.ID)
	if err != nil {
		fmt.Printf("获取二维码失败: %v\n", err)
		qrCodePath = "" // 如果获取失败，不显示二维码
	} else {
		fmt.Printf("二维码生成成功，路径: %s\n", qrCodePath)
	}

	// 构建PDF数据
	orderData := map[string]interface{}{
		"id":         order.ID,
		"customer":   order.Customer.Name,
		"date":       order.OrderDate.Format("2025-07-25"),
		"order_no":   order.OrderNo,
		"creator":    order.Creator.Name,
		"total":      fmt.Sprintf("%.2f", order.TotalAmount),
		"total_text": c.ConvertAmountToChinese(order.TotalAmount),
		"items":      items,
		"status":     string(order.Status),
		"remark":     order.Remark,
		"qr_code":    qrCodePath, // 添加二维码路径
	}

	// 创建PDF
	pdf, err := utils.CreateOrderPDF(orderData)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "生成PDF失败: " + err.Error()})
		return
	}

	// 设置响应头
	ctx.Header("Content-Type", "application/pdf")
	ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=order_%d.pdf", id))

	// 输出PDF
	err = pdf.Output(ctx.Writer)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "输出PDF失败: " + err.Error()})
		return
	}
}

// ConvertAmountToChinese 将金额转换为中文大写
func (c *PDFController) ConvertAmountToChinese(amount float64) string {
	digits := []string{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}
	units := []string{"", "拾", "佰", "仟"}
	bigUnits := []string{"", "万", "亿"}

	if amount == 0 {
		return "零元整"
	}

	// 分离整数和小数部分
	intPart := int(amount)
	decPart := int((amount-float64(intPart))*100 + 0.5) // 四舍五入到分

	var result string

	// 处理整数部分
	if intPart == 0 {
		result = "零"
	} else {
		result = c.convertIntegerPart(intPart, digits, units, bigUnits)
	}

	result += "元"

	// 处理小数部分（角分）
	if decPart == 0 {
		result += "整"
	} else {
		jiao := decPart / 10
		fen := decPart % 10

		if jiao > 0 {
			result += digits[jiao] + "角"
		}
		if fen > 0 {
			if jiao == 0 && intPart > 0 {
				result += "零"
			}
			result += digits[fen] + "分"
		}
	}

	return result
}

// convertIntegerPart 转换整数部分
func (c *PDFController) convertIntegerPart(num int, digits, units, bigUnits []string) string {
	if num == 0 {
		return ""
	}

	var result string
	unitIndex := 0

	// 处理万以下的数字
	for num > 0 && unitIndex < len(bigUnits) {
		part := num % 10000
		if part > 0 {
			partStr := c.convertThousands(part, digits, units)
			if unitIndex > 0 {
				partStr += bigUnits[unitIndex]
			}
			if result != "" && part < 1000 {
				result = "零" + result
			}
			result = partStr + result
		}
		num /= 10000
		unitIndex++
	}

	return result
}

// convertThousands 转换千位以下的数字
func (c *PDFController) convertThousands(num int, digits, units []string) string {
	if num == 0 {
		return ""
	}

	var result string
	needZero := false

	for i := 3; i >= 0; i-- {
		digit := num / pow10(i)
		num %= pow10(i)

		if digit > 0 {
			if needZero {
				result += "零"
			}
			result += digits[digit]
			if i > 0 {
				result += units[i]
			}
			needZero = false
		} else if result != "" {
			needZero = true
		}
	}

	return result
}

// pow10 计算10的n次方
func pow10(n int) int {
	result := 1
	for i := 0; i < n; i++ {
		result *= 10
	}
	return result
}

// 微信访问令牌响应
type AccessTokenResponse struct {
	AccessToken string `json:"access_token"`
	ExpiresIn   int    `json:"expires_in"`
	ErrCode     int    `json:"errcode"`
	ErrMsg      string `json:"errmsg"`
}

// 小程序码请求参数
type QRCodeRequest struct {
	Scene      string `json:"scene"`
	Page       string `json:"page,omitempty"`
	CheckPath  bool   `json:"check_path"`
	EnvVersion string `json:"env_version"`
	Width      int    `json:"width"`
}

// getWechatQRCode 获取微信小程序二维码
func (c *PDFController) getWechatQRCode(orderID uint) (string, error) {

	// 加载微信小程序配置
	wechatConfig, err := config.LoadWechatConfig()
	if err != nil {
		return "", fmt.Errorf("加载微信配置失败: %v", err)
	}
	fmt.Printf("微信配置加载成功: AppID=%s, Page=%s, Query=%s\n", wechatConfig.AppID, wechatConfig.Page, wechatConfig.Query)
	accessToken, err := c.getAccessToken(*wechatConfig)
	if err != nil {
		return "", fmt.Errorf("获取访问令牌失败: %v", err)
	}
	qrCodePath, err := c.generateQRCode(accessToken, orderID, *wechatConfig)
	if err != nil {
		return "", fmt.Errorf("生成小程序码失败: %v", err)
	}
	fmt.Printf("小程序码生成成功: %s\n", qrCodePath)
	return qrCodePath, nil
}

// getAccessToken 获取微信访问令牌
func (c *PDFController) getAccessToken(wechatConfig config.WechatConfig) (string, error) {
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
		wechatConfig.AppID, wechatConfig.AppSecret)

	resp, err := http.Get(url)
	if err != nil {
		return "", fmt.Errorf("HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取响应失败: %v", err)
	}

	var tokenResp AccessTokenResponse
	if err := json.Unmarshal(body, &tokenResp); err != nil {
		return "", fmt.Errorf("JSON解析失败: %v", err)
	}

	if tokenResp.ErrCode != 0 {
		return "", fmt.Errorf("微信API错误[%d]: %s", tokenResp.ErrCode, tokenResp.ErrMsg)
	}
	return tokenResp.AccessToken, nil
}

// generateQRCode 生成小程序码
func (c *PDFController) generateQRCode(accessToken string, orderID uint, wechatConfig config.WechatConfig) (string, error) {
	// 创建二维码存储目录
	qrDir := "assets/qrcodes"
	if err := os.MkdirAll(qrDir, 0755); err != nil {
		return "", fmt.Errorf("创建二维码目录失败: %v", err)
	}

	// 清理该订单的旧二维码文件
	c.cleanOldQRCodes(qrDir, orderID)

	// 使用最简单的场景值格式
	scene := fmt.Sprintf("order%d", orderID)

	// 确保场景值不超过32个字符且符合格式要求
	if len(scene) > 32 {
		scene = scene[:32]
		fmt.Printf("⚠️  场景值超长，已截断到32字符\n")
	}

	qrRequest := QRCodeRequest{
		Scene:      scene,                   // 使用配置的场景值
		Page:       wechatConfig.Page,       // 小程序页面路径，从配置读取
		CheckPath:  false,                   // 不检查页面是否存在
		EnvVersion: wechatConfig.EnvVersion, // 环境版本，从配置读取
		Width:      wechatConfig.Width,      // 二维码宽度，从配置读取
	}
	// 序列化请求参数
	requestBody, err := json.Marshal(qrRequest)
	if err != nil {
		return "", fmt.Errorf("序列化请求参数失败: %v", err)
	}

	// 调用微信API
	url := fmt.Sprintf("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s", accessToken)

	resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody))
	if err != nil {
		fmt.Printf("❌ HTTP请求失败: %v\n", err)
		return "", fmt.Errorf("调用微信API失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		fmt.Printf("❌ HTTP状态码错误: %d\n", resp.StatusCode)
		return "", fmt.Errorf("微信API返回错误状态: %d", resp.StatusCode)
	}

	// 读取响应内容
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("❌ 读取响应失败: %v\n", err)
		return "", fmt.Errorf("读取响应失败: %v", err)
	}

	// 检查是否返回错误信息（JSON格式）
	if bytes.Contains(body, []byte("errcode")) {
		var errorResp map[string]interface{}
		if err := json.Unmarshal(body, &errorResp); err == nil {
			if errCode, ok := errorResp["errcode"].(float64); ok && errCode != 0 {
				errMsg, _ := errorResp["errmsg"].(string)
				fmt.Printf("❌ 微信API错误[%.0f]: %s\n", errCode, errMsg)
				fmt.Printf("📄 完整错误响应: %s\n", string(body))
				return "", fmt.Errorf("微信API错误[%.0f]: %s", errCode, errMsg)
			}
		}
	}

	// 验证响应是否为图片数据
	if len(body) < 100 {
		return "", fmt.Errorf("响应数据异常，大小: %d", len(body))
	}

	// 检查JPEG文件头
	if len(body) >= 2 && body[0] == 0xFF && body[1] == 0xD8 {
		fmt.Printf("✅ 检测到有效的JPEG图片数据\n")
	} else {
		previewLen := 10
		if len(body) < previewLen {
			previewLen = len(body)
		}
		fmt.Printf("❌ 响应数据不是JPEG格式，前几个字节: %x\n", body[:previewLen])
		fmt.Printf("响应内容: %s\n", string(body[:previewLen]))
		return "", fmt.Errorf("微信API返回的不是图片数据")
	}

	// 生成文件名（使用时间戳避免重复）
	filename := fmt.Sprintf("qrcode_order_%d_%d.jpg", orderID, time.Now().Unix())
	filePath := filepath.Join(qrDir, filename)

	// 保存二维码图片
	file, err := os.Create(filePath)
	if err != nil {
		fmt.Printf("❌ 创建文件失败: %v\n", err)
		return "", fmt.Errorf("创建文件失败: %v", err)
	}
	defer file.Close()

	// 写入微信API返回的图片数据
	bytesWritten, err := file.Write(body)
	if err != nil {
		fmt.Printf("❌ 写入文件失败: %v\n", err)
		return "", fmt.Errorf("写入文件失败: %v", err)
	}

	fmt.Printf("✅ 二维码文件保存成功: %s (%d 字节)\n", filePath, bytesWritten)

	return filePath, nil
}

// cleanOldQRCodes 清理指定订单的旧二维码文件
func (c *PDFController) cleanOldQRCodes(qrDir string, orderID uint) {
	fmt.Printf("🧹 清理订单 %d 的旧二维码文件...\n", orderID)

	// 读取目录中的所有文件
	files, err := os.ReadDir(qrDir)
	if err != nil {
		fmt.Printf("⚠️  读取二维码目录失败: %v\n", err)
		return
	}

	// 查找并删除该订单的旧文件
	pattern := fmt.Sprintf("qrcode_order_%d_", orderID)
	deletedCount := 0

	for _, file := range files {
		if !file.IsDir() && filepath.Ext(file.Name()) == ".jpg" {
			fileName := file.Name()
			// 检查文件名是否匹配该订单（安全检查长度）
			if len(fileName) >= len(pattern) && fileName[:len(pattern)] == pattern {
				filePath := filepath.Join(qrDir, fileName)
				if err := os.Remove(filePath); err != nil {
					fmt.Printf("⚠️  删除旧二维码文件失败: %s, 错误: %v\n", filePath, err)
				} else {
					fmt.Printf("🗑️  已删除旧二维码文件: %s\n", fileName)
					deletedCount++
				}
			}
		}
	}

	if deletedCount > 0 {
		fmt.Printf("✅ 共删除 %d 个旧二维码文件\n", deletedCount)
	} else {
		fmt.Printf("ℹ️  没有找到需要删除的旧二维码文件\n")
	}
}
